<template>
  <div class="pdf-viewer">
    <!-- PDF内容区域 -->
    <div class="pdf-content" ref="pdfContent">
      <div class="pdf-canvas-container" ref="canvasContainer">
        <canvas ref="pdfCanvas" class="pdf-canvas"></canvas>
      </div>
      <div v-if="loading" class="pdf-loading">
        <i class="el-icon-loading"></i>
        <p>正在加载PDF...</p>
      </div>
      <div v-if="error" class="pdf-error">
        <i class="el-icon-warning"></i>
        <p>{{ error }}</p>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: 'PdfViewer',
  props: {
    url: {
      type: String,
      required: true
    },
    zoom: {
      type: Number,
      default: 1
    },
    page: {
      type: Number,
      default: 1
    }
  },
  data() {
    return {
      pdfDoc: null,
      currentPage: 1,
      totalPages: 0,
      loading: false,
      error: null,
      canvas: null,
      ctx: null,
      // 拖拽相关
      isDragging: false,
      dragStartX: 0,
      dragStartY: 0,
      canvasOffsetX: 0,
      canvasOffsetY: 0,
      lastCanvasOffsetX: 0,
      lastCanvasOffsetY: 0,
      // 容器尺寸
      containerWidth: 0,
      containerHeight: 0,
      // 缩放相关
      lastZoom: undefined,
      // 是否已经初始化过中心位置
      hasInitializedCenter: false
    }
  },
  watch: {
    url: {
      immediate: true,
      handler(newUrl) {
        if (newUrl) {
          this.loadPdf(newUrl);
        }
      }
    },
    zoom(newZoom, oldZoom) {
      // 缩放时保持当前位置
      this.renderPageWithZoomPreservation(newZoom, oldZoom);
    },
    page: {
      immediate: true,
      handler(newPage) {
        if (this.pdfDoc && newPage >= 1 && newPage <= this.totalPages) {
          this.currentPage = newPage;
          this.renderPage();
        }
      }
    }
  },
  methods: {
    async loadPdf(url) {
      this.loading = true;
      this.error = null;
      
      try {
        // 动态加载PDF.js
        if (!window.pdfjsLib) {
          await this.loadPdfJs();
        }
        
        const loadingTask = window.pdfjsLib.getDocument(url);
        this.pdfDoc = await loadingTask.promise;
        this.totalPages = this.pdfDoc.numPages;
        this.currentPage = Math.min(this.page, this.totalPages);
        
        this.$emit('loaded', {
          totalPages: this.totalPages,
          currentPage: this.currentPage
        });
        
        await this.renderPage();
      } catch (err) {
        console.error('PDF加载失败:', err);
        this.error = 'PDF加载失败: ' + err.message;
        this.$emit('error', err);
      } finally {
        this.loading = false;
      }
    },
    
    async loadPdfJs() {
      return new Promise((resolve, reject) => {
        // 检查是否已经加载
        if (window.pdfjsLib) {
          resolve();
          return;
        }
        
        // 动态加载PDF.js
        const script = document.createElement('script');
        script.src = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.min.js';
        script.onload = () => {
          window.pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js';
          resolve();
        };
        script.onerror = reject;
        document.head.appendChild(script);
      });
    },
    
    // 获取容器尺寸
    updateContainerSize() {
      const container = this.$refs.canvasContainer;
      if (container) {
        this.containerWidth = container.clientWidth;
        this.containerHeight = container.clientHeight;
      }
    },
    
    // 计算PDF垂直平分线的中心位置
    calculateCenterPosition(viewport) {
      this.updateContainerSize();
      
      // 计算PDF的垂直平分线位置
      const pdfCenterX = viewport.width / 2;
      const pdfCenterY = viewport.height / 2;
      
      // 计算容器中心
      const containerCenterX = this.containerWidth / 2;
      const containerCenterY = this.containerHeight / 2;
      
      // 计算偏移量，使PDF的垂直平分线位于容器中心
      const offsetX = containerCenterX - pdfCenterX;
      const offsetY = containerCenterY - pdfCenterY;
      
      return { offsetX, offsetY };
    },
    
    // 保存当前视口中心点
    saveViewportCenter() {
      // 保存当前的缩放比例和偏移量
      this.lastZoom = this.zoom;
      this.lastCanvasOffsetX = this.canvasOffsetX;
      this.lastCanvasOffsetY = this.canvasOffsetY;
    },
    
    // 根据保存的中心点计算新的偏移量
    calculateOffsetFromCenter(viewport) {
      this.updateContainerSize();
      
      // 如果没有保存的上一次状态，则居中显示
      if (this.lastZoom === undefined) {
        const { offsetX, offsetY } = this.calculateCenterPosition(viewport);
        return { offsetX, offsetY };
      }
      
      // 计算缩放比例的变化
      const zoomRatio = this.zoom / this.lastZoom;
      
      // 根据缩放比例调整偏移量
      const offsetX = this.lastCanvasOffsetX * zoomRatio;
      const offsetY = this.lastCanvasOffsetY * zoomRatio;
      
      return { offsetX, offsetY };
    },
    
    async renderPage() {
      if (!this.pdfDoc || !this.canvas) return;

      try {
        this.loading = true;
        this.error = null;

        const page = await this.pdfDoc.getPage(this.currentPage);
        const viewport = page.getViewport({ scale: this.zoom });

        // 设置canvas尺寸
        this.canvas.width = viewport.width;
        this.canvas.height = viewport.height;

        // 渲染页面
        const renderContext = {
          canvasContext: this.ctx,
          viewport: viewport
        };

        await page.render(renderContext).promise;

        // 初始化或重置canvas位置
        if (!this.hasInitializedCenter) {
          // 首次加载：以PDF垂直平分线为中心
          const { offsetX, offsetY } = this.calculateCenterPosition(viewport);
          this.canvasOffsetX = offsetX;
          this.canvasOffsetY = offsetY;
          this.hasInitializedCenter = true;
          // 重置缩放状态
          this.lastZoom = undefined;
        } else {
          // 页面切换：重置到中心位置
          const { offsetX, offsetY } = this.calculateCenterPosition(viewport);
          this.canvasOffsetX = offsetX;
          this.canvasOffsetY = offsetY;
          // 重置缩放状态
          this.lastZoom = undefined;
        }
        
        this.updateCanvasPosition();
        
        // 初始化拖拽事件
        this.$nextTick(() => {
          this.initDragEvents();
        });

        this.$emit('pageRendered', {
          page: this.currentPage,
          totalPages: this.totalPages,
          viewport: viewport
        });

      } catch (err) {
        console.error('PDF页面渲染失败:', err);
        this.error = '页面渲染失败: ' + err.message;
        this.$emit('error', err);
      } finally {
        this.loading = false;
      }
    },
    
    // 缩放时保持当前位置的渲染方法
    async renderPageWithZoomPreservation(newZoom, oldZoom) {
      if (!this.pdfDoc || !this.canvas) return;

      try {
        this.loading = true;
        this.error = null;

        // 保存当前视口中心点
        this.saveViewportCenter();

        const page = await this.pdfDoc.getPage(this.currentPage);
        const viewport = page.getViewport({ scale: newZoom });

        // 设置canvas尺寸
        this.canvas.width = viewport.width;
        this.canvas.height = viewport.height;

        // 渲染页面
        const renderContext = {
          canvasContext: this.ctx,
          viewport: viewport
        };

        await page.render(renderContext).promise;

        // 根据保存的中心点计算新的偏移量
        const { offsetX, offsetY } = this.calculateOffsetFromCenter(viewport);
        this.canvasOffsetX = offsetX;
        this.canvasOffsetY = offsetY;
        
        this.updateCanvasPosition();

        this.$emit('pageRendered', {
          page: this.currentPage,
          totalPages: this.totalPages,
          viewport: viewport
        });

      } catch (err) {
        console.error('PDF页面缩放渲染失败:', err);
        this.error = '页面渲染失败: ' + err.message;
        this.$emit('error', err);
      } finally {
        this.loading = false;
      }
    },
    
    // 公共方法
    goToPage(pageNum) {
      if (pageNum >= 1 && pageNum <= this.totalPages) {
        this.currentPage = pageNum;
        this.$emit('pageChanged', pageNum);
        this.renderPage();
      }
    },
    
    nextPage() {
      if (this.currentPage < this.totalPages) {
        this.goToPage(this.currentPage + 1);
      }
    },
    
    prevPage() {
      if (this.currentPage > 1) {
        this.goToPage(this.currentPage - 1);
      }
    },

    // 拖拽相关方法
    initDragEvents() {
      const container = this.$refs.canvasContainer;
      if (!container) return;

      // 鼠标事件
      container.addEventListener('mousedown', this.onMouseDown);
      document.addEventListener('mousemove', this.onMouseMove);
      document.addEventListener('mouseup', this.onMouseUp);

      // 触摸事件
      container.addEventListener('touchstart', this.onTouchStart);
      document.addEventListener('touchmove', this.onTouchMove);
      document.addEventListener('touchend', this.onTouchEnd);

      // 防止拖拽时选中文本
      container.addEventListener('selectstart', (e) => e.preventDefault());
    },

    removeDragEvents() {
      document.removeEventListener('mousemove', this.onMouseMove);
      document.removeEventListener('mouseup', this.onMouseUp);
      document.removeEventListener('touchmove', this.onTouchMove);
      document.removeEventListener('touchend', this.onTouchEnd);
    },

    onMouseDown(e) {
      this.isDragging = true;
      this.dragStartX = e.clientX;
      this.dragStartY = e.clientY;
      this.lastCanvasOffsetX = this.canvasOffsetX;
      this.lastCanvasOffsetY = this.canvasOffsetY;
      e.preventDefault();
    },

    onMouseMove(e) {
      if (!this.isDragging) return;
      
      const deltaX = e.clientX - this.dragStartX;
      const deltaY = e.clientY - this.dragStartY;
      
      this.canvasOffsetX = this.lastCanvasOffsetX + deltaX;
      this.canvasOffsetY = this.lastCanvasOffsetY + deltaY;
      
      this.updateCanvasPosition();
      e.preventDefault();
    },

    onMouseUp() {
      this.isDragging = false;
    },

    onTouchStart(e) {
      if (e.touches.length === 1) {
        this.isDragging = true;
        this.dragStartX = e.touches[0].clientX;
        this.dragStartY = e.touches[0].clientY;
        this.lastCanvasOffsetX = this.canvasOffsetX;
        this.lastCanvasOffsetY = this.canvasOffsetY;
      }
    },

    onTouchMove(e) {
      if (!this.isDragging || e.touches.length !== 1) return;
      
      const deltaX = e.touches[0].clientX - this.dragStartX;
      const deltaY = e.touches[0].clientY - this.dragStartY;
      
      this.canvasOffsetX = this.lastCanvasOffsetX + deltaX;
      this.canvasOffsetY = this.lastCanvasOffsetY + deltaY;
      
      this.updateCanvasPosition();
      e.preventDefault();
    },

    onTouchEnd() {
      this.isDragging = false;
    },

    updateCanvasPosition() {
      if (this.canvas) {
        this.canvas.style.transform = `translate(${this.canvasOffsetX}px, ${this.canvasOffsetY}px)`;
      }
    },

    resetCanvasPosition() {
      this.canvasOffsetX = 0;
      this.canvasOffsetY = 0;
      this.updateCanvasPosition();
    },
  },
  mounted() {
    this.canvas = this.$refs.pdfCanvas;
    this.ctx = this.canvas.getContext('2d');
    
    // 监听窗口大小变化
    window.addEventListener('resize', this.updateContainerSize);
  },
  beforeDestroy() {
    this.removeDragEvents();
    window.removeEventListener('resize', this.updateContainerSize);
  }
}
</script>

<style scoped>
.pdf-viewer {
  position: relative;
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  background: #f8f9fa;
}

.pdf-navigation {
  position: sticky;
  top: 0;
  background: #f5f7fa;
  padding: 8px 16px;
  border-bottom: 1px solid #e4e7ed;
  z-index: 10;
  display: flex;
  justify-content: center;
  align-items: center;
}

.pdf-content {
  flex: 1;
  overflow: auto;
  position: relative;
  background: #f8f9fa;
}

.pdf-canvas-container {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
  cursor: grab;
}

.pdf-canvas-container:active {
  cursor: grabbing;
}

.pdf-canvas {
  display: block;
  margin: 0;
  transition: transform 0.1s ease-out;
  user-select: none;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
}

.pdf-loading,
.pdf-error {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  text-align: center;
  color: #909399;
}

.pdf-loading i,
.pdf-error i {
  font-size: 24px;
  margin-bottom: 8px;
  display: block;
}

.pdf-error {
  color: #f56c6c;
}
</style> 